/*
 * Created by Jaren at 2021/10/29 15:45
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/common/assistant_settings.dart';
import 'package:inmotion_protocol/common/vehicle_info.dart';
import 'package:inmotion_protocol/ezcan/bean/settings.dart';
import 'package:inmotion_protocol/ezcan/ezcan_constant.dart';
import 'package:inmotion_protocol/util/byte_util.dart';
import 'package:inmotion_protocol/util/version.dart';

abstract class EBikeSettings extends AbsSettings {
  static const int speedUnitKmph = 0; // 车辆速度单位，Km/h
  static const int speedUnitMph = 1; // 车辆速度单位，mph

  static const int lightOff = 0; // 前灯关
  static const int lightOn = 0xFF; // 前灯开

  Uint4 zeroStartupState = Uint4.zero; // 零速启动开关
  Uint4 cruiseState = Uint4.zero; // 定速巡航开关

  Uint4 lockState = Uint4.zero; // 锁车

  Uint16 limitSpeed = Uint16.zero; // 限速

  EBikeSettings.fromSlowRspBytes(Uint8ClampedList slowInfoRspMsgExtraBytes) {
    cruiseState = ByteUtil.toUint4(ByteUtil.bytes2Uint32Le(slowInfoRspMsgExtraBytes, 56).value);
    limitSpeed = ByteUtil.toUint16(ByteUtil.bytes2Uint32Le(slowInfoRspMsgExtraBytes, 60).value ~/ 10);
  }
}

class AssistanceSettings extends AbsAssistanceSettings {
  final ProductProperty _property;
  EBikeAssistanceCompact? _compact;

  static const int ridingModeEco = 0;
  static const int ridingModeNormal = 1;
  static const int ridingModeSpeed = 2;
  static const int ridingModeStudy = 3;

  /*        助力模式 无助力/轻助力/强助力       *
     **      各模式的值无实际含义，仅作标识用     */
  static const int assistantModeNone = 0;
  static const int assistantModeMedium = 1;
  static const int assistantModeMax = 2;

  Uint8 assistanceForce = Uint8.zero; // 助力强度
  Uint8 assistanceStartupSensitivity = Uint8.zero; // 助力启动灵敏度 1-100  低:50  高:100
  Uint8 assistanceStartupForce = Uint8.zero; // 助力启动强度 0-100  0:0  1:8  2:28
  Uint8 assistanceStartupSpeed = Uint8.zero; // 助力启动速度(单位: 0.1km/h) 0-50
  Uint8 acceleratorStartupForce = Uint8.zero; // 油门启动强度 0-100
  Uint8 maxPowerLimit = Uint8.zero; // 最大功率百分比限制 1-100
  Uint8 ridingMode = Uint8.zero; // 骑行模式，此参数对车辆不起实质性作用，仅存储于车内，用于给APP识别骑行模式
  Uint8 limitSpeed = Uint8.zero; // 限速，单位4，即如果需要设置为9Km/h，则maxSpeed值为4×9=36

  AssistanceSettings(this._property) {
    _initCompact();
  }

  void _initCompact() {
    String btVersion = _property.versionWrapper.getAppVersionByDevice(EzcanConstant.E_BIKE_DEVICE_PC);
    if (_property.model.isP2Like() && VersionUtils.higherOrEquals(btVersion, "1.2.10")) {
      _compact = EBikeAssistanceV2(this);
    } else {
      _compact = EBikeAssistanceV1(this);
    }
  }

  AssistanceSettings.fromBytes(this._property, Uint8ClampedList bytes) {
    _initCompact();
    assistanceForce = ByteUtil.toUint8(bytes[0] & 0x7f);
    assistanceStartupSensitivity = ByteUtil.toUint8(bytes[1] & 0x7F);
    assistanceStartupForce = ByteUtil.toUint8(bytes[2] & 0xFF);
    assistanceStartupSpeed = ByteUtil.toUint8(bytes[3] & 0xFF);
    acceleratorStartupForce = ByteUtil.toUint8(bytes[4] & 0xFF);
    maxPowerLimit = ByteUtil.toUint8(bytes[5] & 0xFF);
    ridingMode = ByteUtil.toUint8(bytes[6] & 0x0F);
  }

  int getAssistantMode() {
    return _compact!.getAssistantMode();
  }

  void updateByAssistanceMode(int assistanceMode) {
    return _compact!.updateByAssistanceMode(assistanceMode);
  }

  void updateByRidingMode(int ridingMode) {
    return _compact!.updateByRidingMode(ridingMode);
  }

  void updateByZeroSpeedStartUp(bool on) {
    return _compact!.updateByZeroSpeedStartUp(on);
  }

  bool isZeroStartOn() {
    return _compact!.isZeroStartOn();
  }

  AssistanceSettings copy() {
    AssistanceSettings another = AssistanceSettings(_property);
    another._compact = _compact!.copy(another);

    another.assistanceForce = ByteUtil.toUint8(assistanceForce.value);
    another.assistanceStartupSensitivity = ByteUtil.toUint8(assistanceStartupSensitivity.value);
    another.assistanceStartupForce = ByteUtil.toUint8(assistanceStartupForce.value);
    another.assistanceStartupSpeed = ByteUtil.toUint8(assistanceStartupSpeed.value);
    another.acceleratorStartupForce = ByteUtil.toUint8(acceleratorStartupForce.value);
    another.maxPowerLimit = ByteUtil.toUint8(maxPowerLimit.value);
    another.ridingMode = ByteUtil.toUint8(ridingMode.value);
    another.limitSpeed = ByteUtil.toUint8(limitSpeed.value);

    return another;
  }

  @override
  String toString() {
    return 'AssistanceSettings{_compact: $_compact, assistanceForce: ${assistanceForce.value}, '
        'assistanceStartupSensitivity: ${assistanceStartupSensitivity.value}, assistanceStartupForce: ${assistanceStartupForce.value},'
        ' assistanceStartupSpeed: ${assistanceStartupSpeed.value}, acceleratorStartupForce: ${acceleratorStartupForce.value}, '
        'maxPowerLimit: ${maxPowerLimit.value}, ridingMode: ${ridingMode.value}, limitSpeed: ${limitSpeed.value}';
  }
}

abstract class EBikeAssistanceCompact {
  final AssistanceSettings _settings;

  EBikeAssistanceCompact(this._settings);

  int getAssistantMode();

  void updateByAssistanceMode(int assistanceMode);

  void updateByRidingMode(int ridingMode);

  void updateByZeroSpeedStartUp(bool on);

  bool isZeroStartOn();

  EBikeAssistanceCompact copy(AssistanceSettings settings);
}

class EBikeAssistanceV1 extends EBikeAssistanceCompact {
  EBikeAssistanceV1(AssistanceSettings settings) : super(settings);

  @override
  int getAssistantMode() {
    int assistanceForce = _settings.assistanceForce.value;
    if (assistanceForce >= 0x7F) {
      return AssistanceSettings.assistantModeNone;
    } else if (assistanceForce <= 8) {
      return AssistanceSettings.assistantModeMedium;
    } else {
      return AssistanceSettings.assistantModeMax;
    }
  }

  @override
  void updateByAssistanceMode(int assistanceMode) {
    if (assistanceMode == AssistanceSettings.assistantModeMax) {
      _settings.assistanceStartupForce = ByteUtil.toUint8(28);
    } else if (assistanceMode == AssistanceSettings.assistantModeMedium) {
      _settings.assistanceStartupForce = ByteUtil.toUint8(8);
    } else if (assistanceMode == AssistanceSettings.assistantModeNone) {
      _settings.assistanceStartupForce = ByteUtil.toUint8(0);
    }
  }

  @override
  void updateByRidingMode(int ridingMode) {
    if (ridingMode == AssistanceSettings.ridingModeEco) {
      _settings.assistanceForce = ByteUtil.toUint8(33);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(50);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(50);
      _settings.maxPowerLimit = ByteUtil.toUint8(50);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(15 * 4);
    } else if (ridingMode == AssistanceSettings.ridingModeNormal) {
      _settings.assistanceForce = ByteUtil.toUint8(33);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(0);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(80);
      _settings.maxPowerLimit = ByteUtil.toUint8(80);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(20 * 4);
    } else if (ridingMode == AssistanceSettings.ridingModeSpeed) {
      _settings.assistanceForce = ByteUtil.toUint8(33);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(0);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(100);
      _settings.maxPowerLimit = ByteUtil.toUint8(100);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(_settings._property.getDefaultDesignedMaxSpeed() * 100 * 4);
    } else if (ridingMode == AssistanceSettings.ridingModeStudy) {
      _settings.assistanceForce = ByteUtil.toUint8(33);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(0);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(30);
      _settings.maxPowerLimit = ByteUtil.toUint8(0);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(9 * 4);
    }
  }

  @override
  void updateByZeroSpeedStartUp(bool on) {
    throw UnsupportedError('V1 version does not support zero speed startup function.');
  }

  @override
  EBikeAssistanceCompact copy(AssistanceSettings settings) {
    EBikeAssistanceV1 compact = EBikeAssistanceV1(settings);
    return compact;
  }

  @override
  bool isZeroStartOn() {
    return false;
  }
}

class EBikeAssistanceV2 extends EBikeAssistanceCompact {
  EBikeAssistanceV2(AssistanceSettings settings) : super(settings);

  @override
  int getAssistantMode() {
    int assistanceForce = _settings.assistanceForce.value;
    if (assistanceForce == 100) {
      return AssistanceSettings.assistantModeMax;
    } else if (assistanceForce == 50) {
      return AssistanceSettings.assistantModeMedium;
    } else {
      return AssistanceSettings.assistantModeNone;
    }
  }

  @override
  void updateByAssistanceMode(int assistanceMode) {
    if (assistanceMode == AssistanceSettings.assistantModeMax) {
      _settings.assistanceForce = ByteUtil.toUint8(100 | 0x80);
    } else if (assistanceMode == AssistanceSettings.assistantModeMedium) {
      _settings.assistanceForce = ByteUtil.toUint8(50 | 0x80);
    } else if (assistanceMode == AssistanceSettings.assistantModeNone) {
      _settings.assistanceForce = ByteUtil.toUint8(0 | 0x80);
    }
  }

  @override
  void updateByRidingMode(int ridingMode) {
    if (ridingMode == AssistanceSettings.ridingModeEco) {
      _settings.assistanceForce = ByteUtil.toUint8(_settings.assistanceForce.value | 0x80);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupForce = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(50);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(50);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(15 * 4);
    } else if (ridingMode == AssistanceSettings.ridingModeNormal) {
      _settings.assistanceForce = ByteUtil.toUint8(_settings.assistanceForce.value | 0x80);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupForce = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(0);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(50);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(20 * 4);
    } else if (ridingMode == AssistanceSettings.ridingModeSpeed) {
      _settings.assistanceForce = ByteUtil.toUint8(_settings.assistanceForce.value | 0x80);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupForce = ByteUtil.toUint8(100);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(100);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(100);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(_settings._property.getDefaultDesignedMaxSpeed() * 100 * 4);
    } else if (ridingMode == AssistanceSettings.ridingModeStudy) {
      _settings.assistanceForce = ByteUtil.toUint8(0);
      _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
      _settings.assistanceStartupForce = ByteUtil.toUint8(0);
      _settings.assistanceStartupSpeed = ByteUtil.toUint8(0);
      _settings.acceleratorStartupForce = ByteUtil.toUint8(30);
      _settings.ridingMode = ByteUtil.toUint8(ridingMode);
      _settings.limitSpeed = ByteUtil.toUint8(9 * 4);
    }
  }

  @override
  void updateByZeroSpeedStartUp(bool on) {
    _settings.assistanceForce = ByteUtil.toUint8(_settings.assistanceForce.value | 0x80);
    _settings.assistanceStartupSensitivity = ByteUtil.toUint8(100);
    _settings.assistanceStartupForce = ByteUtil.toUint8(100);
    _settings.assistanceStartupSpeed = ByteUtil.toUint8(on ? 0 : 50);
    _settings.acceleratorStartupForce = ByteUtil.toUint8(50);
  }

  @override
  bool isZeroStartOn() {
    return _settings.assistanceStartupSpeed.value == 0;
  }

  @override
  EBikeAssistanceCompact copy(AssistanceSettings settings) {
    EBikeAssistanceV2 compact = EBikeAssistanceV2(settings);
    return compact;
  }
}

class P1Settings extends EBikeSettings {
  P1Settings.fromSlowRspBytes(Uint8ClampedList slowInfoRspMsgExtraBytes, [int offset = 0]) : super.fromSlowRspBytes(slowInfoRspMsgExtraBytes);
}

class P2LikeSettings extends EBikeSettings {
  /// 助力参数相关设置项
  AssistanceSettings? assistanceSettings;

  Uint4 overspeedWarningState = Uint4.zero; // 超速报警开关
  Uint8 ridingMode = ByteUtil.toUint8(AssistanceSettings.ridingModeNormal); // 骑行模式
  Uint8 assistantMode = ByteUtil.toUint8(AssistanceSettings.assistantModeNone); // 助力模式

  P2LikeSettings.fromSlowRspBytes(Uint8ClampedList slowInfoRspMsgExtraBytes) : super.fromSlowRspBytes(slowInfoRspMsgExtraBytes) {
    if (slowInfoRspMsgExtraBytes.length > 129) overspeedWarningState = ByteUtil.bitValue(slowInfoRspMsgExtraBytes[129], 4, 1);
  }

  @override
  String toString() {
    return 'P2LikeSettings{assistanceSettings: ${assistanceSettings.toString()}, {zeroStartupState: ${zeroStartupState.value}, '
        'cruiseState: ${cruiseState.value}, lockState: ${lockState.value}, limitSpeed: ${limitSpeed.value}, '
        'overspeedWarningState: ${overspeedWarningState.value}, ridingMode: ${ridingMode.value}, assistantMode: ${assistantMode.value}';
  }
}
